/*****************************************************************************
 *                                                                           *
 * Module:       Peripheral_on_External_Bus                                  *
 * Description:                                                              *
 *      This module is used for the registers for part I of the bus          *
 *   communication exercise in Altera's computer organization lab set.       *
 *                                                                           *
 *****************************************************************************/

module Peripheral_on_External_Bus (
	// Inputs
	clk,
	reset_n,
	
	address,
	bus_enable,
	byte_enable,
	rw,
	write_data,
	
	// Bidirectionals
	
	// Outputs
	acknowledge,
	read_data,
	
	register_0,
	register_1,
	register_2,
	register_3
);

/*****************************************************************************
 *                           Parameter Declarations                          *
 *****************************************************************************/


/*****************************************************************************
 *                             Port Declarations                             *
 *****************************************************************************/

// Inputs
input				clk;
input				reset_n;

input		[31:0]	address;
input				bus_enable;
input		[1:0]	byte_enable;
input				rw;
input		[15:0]	write_data;

// Bidirectionals

// Outputs
output				acknowledge;
output		[15:0]	read_data;

output	reg	[15:0]	register_0;
output	reg	[15:0]	register_1;
output	reg	[15:0]	register_2;
output	reg	[15:0]	register_3;

/*****************************************************************************
 *                 Internal Wires and Registers Declarations                 *
 *****************************************************************************/

// Internal Wires
	wire [1:0]regIndex;
	wire isThisDevice;
	
	assign regIndex = address[1:0];
	
//	always @(posedge bus_enable) begin
//		isThisDevice = (address[20:1] == 0x00000000);
//	end
	assign isThisDevice = !(|{address[20:1]});

// Internal Registers

// State Machine Registers
	reg [1:0] current, next;
	reg [15:0] curData;
	parameter [1:0] A=0, B=1, C=2, D=3;

/*****************************************************************************
 *                         Finite State Machine(s)                           *
 *****************************************************************************/
	always @(current) begin
		case(current)
		A: 
		begin
		if(bus_enable && isThisDevice)
			if(rw)
			begin
			//read
				next=C;
			end
			else 
			begin
			//write
				next=B;

			end
		else
			next=A;
		end
		
		B: next=D;
		
		C: next=D;
		
		D: next=A;

		default: next=A;
		endcase
	end

	
assign acknowledge = (current==D); 

assign read_data = curData;

/*****************************************************************************
 *                             Sequential Logic                              *
 *****************************************************************************/

 
always @(posedge clk)
begin
	current <= next;
	case(current)
	B:
	begin
		case(regIndex)
			0:register_0<=write_data;
			1:register_1<=write_data;
			2:register_2<=write_data;
			3:register_3<=write_data;
		endcase
	end
	C:
	begin
		case(regIndex)
			0:curData<=register_0;
			1:curData<=register_1;
			2:curData<=register_2;
			3:curData<=register_3;
		endcase	
	end
	endcase
	if (reset_n == 0)
	begin
		register_0 <= 16'h0000;
		register_1 <= 16'h0000;
		register_2 <= 16'h0000;
		register_3 <= 16'h0000;
	end
end

/*****************************************************************************
 *                            Combinational Logic                            *
 *****************************************************************************/


/*****************************************************************************
 *                              Internal Modules                             *
 *****************************************************************************/


endmodule
